#include "socket.h"
#include "IOmanager.h"
#include "log.h"
#include "fd_manager.h"
#include "hook.h"
#include "macro.h"
#include <ctime>

namespace framework
{
static framework::Logger::ptr g_logger = FRAMEWORK_LOG_NAME("system");


//创建TCP Socket(满足地址类型)
Socket::ptr Socket::CreateTCP(framework::Address::ptr address)
{
    Socket::ptr sock(new Socket(address->getFamily(), TCP, 0));
    return sock;
}

//创建UDP Socket(满足地址类型)
Socket::ptr Socket::CreateUDP(framework::Address::ptr address)
{
    Socket::ptr sock(new Socket(address->getFamily(), UDP, 0));
    sock->newSock();
    sock->m_isConnected = true;
    return sock;
}

//创建IPv4的TCP Socket
Socket::ptr Socket::CreateTCPSocket()
{
    Socket::ptr sock(new Socket(IPv4, TCP, 0));
    return sock;
}

//创建IPv4的UDP Socket
Socket::ptr Socket::CreateUDPSocket()
{
    Socket::ptr sock(new Socket(IPv4, UDP, 0));
    sock->newSock();
    sock->m_isConnected = true;
    return sock;
}

//创建IPv6的TCP Socket
Socket::ptr Socket::CreateTCPSocket6()
{
    Socket::ptr sock(new Socket(IPv6, TCP, 0));
    return sock;
}

//创建IPv6的UDP Socket
Socket::ptr Socket::CreateUDPSocket6()
{
    Socket::ptr sock(new Socket(IPv6, UDP, 0));
    sock->newSock();
    sock->m_isConnected = true;
    return sock;
}

//创建Unix的TCP Socket
Socket::ptr Socket::CreateUnixTCPSocket()
{
    Socket::ptr sock(new Socket(UNIX, TCP, 0));
    return sock;
}

//创建Unix的UDP Socket
Socket::ptr Socket::CreateUnixUDPSocket()
{
    Socket::ptr sock(new Socket(UNIX, UDP, 0));
    return sock;
}

//Socket    构造函数
Socket::Socket(int family, int type, int protocol)
    :m_sock(-1)
    ,m_family(family)
    ,m_type(type)
    ,m_protocol(protocol)
    ,m_isConnected(false) {
    
}

//Socket  析构函数
Socket::~Socket()
{
    close();
}

//获取发送超时时间(毫秒)
int64_t Socket::getSendTimeout()
{
    FDCtx::ptr ctx = FdMgr::GetInstance()->get(m_sock);
    if(ctx)
    {
        //获取发送超时
        return ctx->getTimeout(SO_SNDTIMEO);
    }

    return -1;
}

//设置发送超时时间(毫秒)
void Socket::setSendTimeout(int64_t v)
{
    //秒   微秒
    struct timeval tv{int(v/1000), int(v%1000*1000)};

    //SOL_SOCKET表示设置socket的发送选项
    setOption(SOL_SOCKET, SO_SNDTIMEO, tv);
}

//获取接受超时时间(毫秒)
int64_t Socket::getRecvTimeout()
{
    FDCtx::ptr ctx = FdMgr::GetInstance()->get(m_sock);
    if(ctx)
    {
        //获接收超时
        return ctx->getTimeout(SO_RCVTIMEO);
    }

    return -1;
}

//设置接受超时时间(毫秒)
void Socket::setRecvTimeout(int64_t v)
{
    //秒   微秒
    struct timeval tv{int(v/1000), int(v%1000*1000)};

    //SOL_SOCKET表示设置socket的发送选项
    setOption(SOL_SOCKET, SO_RCVTIMEO, tv);
}

//获取sockopt  getsockopt
bool Socket::getOption(int level, int option, void* result, socklen_t* len)
{
    int rt = getsockopt(m_sock, level, option, result, (socklen_t*)len);
    if(rt)
    {
        FRAMEWORK_LOG_DEBUG(g_logger) << "getOption sock=" << m_sock
            << " level=" << level << " option=" << option
            << " errno=" << errno << " errstr=" << strerror(errno);
        return false;
    }

    return true;
}


//设置sockopt  setsockopt
bool Socket::setOption(int level, int option, const void* result, socklen_t len)
{
    int rt = setsockopt(m_sock, level, option, result, (socklen_t)len);
    if(rt)
    {
        FRAMEWORK_LOG_DEBUG(g_logger) << "setOption sock=" << m_sock
            << " level=" << level << " option=" << option
            << " errno=" << errno << " errstr=" << strerror(errno);
        return false;
    }

    return true;
}


/**
 * @brief 接收connect链接
 * @return 成功返回新连接的socket,失败返回nullptr
 * @pre Socket必须 bind , listen  成功
 */
Socket::ptr Socket::accept()
{
    Socket::ptr sock(new Socket(m_family, m_type, m_protocol));
    int newSock = ::accept(m_sock, nullptr, nullptr);

    if(newSock == -1)
    {
        FRAMEWORK_LOG_ERROR(g_logger) << "accept(" << m_sock << ") errno="
            << errno << " errstr=" << strerror(errno);
        return nullptr;
    }

    if(sock->init(newSock))
    {
        return sock;
    }

    return nullptr;
}

//初始化sock
bool Socket::init(int sock)
{
    FDCtx::ptr ctx = FdMgr::GetInstance()->get(sock);
    if(ctx && ctx->isSocket() && !ctx->isClose())
    {
        m_sock = sock;         //设置地址
        m_isConnected = true;  //设置已链接
        initSock();            //设置sock参数
        getLocalAddress();     //获取本地地址
        getRemoteAddress();    //获取远端地址
        return true;
    }
    return false;
}



/**
 * @brief 绑定地址
 * @param[in] addr 地址
 * @return 是否绑定成功
 */
bool Socket::bind(const Address::ptr addr)
{
    //如果当前m_sock无效
    if(!isValid())
    {
        newSock(); //初始化m_sock
        if(FRAMEWORK_UNLIKELY(!isValid()))
        {
            return false;
        }
    }

    //判断协议族是否正确
    if(FRAMEWORK_UNLIKELY(addr->getFamily() != m_family))
    {
        FRAMEWORK_LOG_ERROR(g_logger) << "bind sock.family("
            << m_family << ") addr.family(" << addr->getFamily()
            << ") not equal, addr=" << addr->toString();
        return false;
    }

    // UnixAddress::ptr uaddr = std::dynamic_pointer_cast<UnixAddress>(addr);
    // if(uaddr) {
    //     Socket::ptr sock = Socket::CreateUnixTCPSocket();
    //     if(sock->connect(uaddr)) {
    //         return false;
    //     } else {
    //         sylar::FSUtil::Unlink(uaddr->getPath(), true);
    //     }
    // }


    if(::bind(m_sock, addr->getAddr(), addr->getAddrLen())) 
    {
        FRAMEWORK_LOG_ERROR(g_logger) << "bind error errrno=" << errno
        << " errstr=" << strerror(errno);
        return false;
    }
    getLocalAddress();
    return true;
}


/**
 * @brief 连接地址
 * @param[in] addr 目标地址
 * @param[in] timeout_ms 超时时间(毫秒)
 */
bool Socket::connect(const Address::ptr addr, uint64_t timeout_ms)
{
    //如果当前m_sock无效
    if(!isValid())
    {
        newSock(); //初始化m_sock
        if(FRAMEWORK_UNLIKELY(!isValid()))
        {
            return false;
        }
    }

    //判断协议族是否正确
    if(FRAMEWORK_UNLIKELY(addr->getFamily() != m_family))
    {
        FRAMEWORK_LOG_ERROR(g_logger) << "bind sock.family("
            << m_family << ") addr.family(" << addr->getFamily()
            << ") not equal, addr=" << addr->toString();
        return false;
    }

    if(timeout_ms == (uint64_t)-1) //如果没有设置超时时间
    {
        if(::connect(m_sock, addr->getAddr(), addr->getAddrLen()))
        {
            FRAMEWORK_LOG_ERROR(g_logger) << "sock=" << m_sock << " connect(" << addr->toString()
                << ") error errno=" << errno << " errstr=" << strerror(errno);
            close();
            return false;
        }
    }
    else
    {
        if(::connect_with_timeout(m_sock, addr->getAddr(), addr->getAddrLen(), timeout_ms))
        {
            FRAMEWORK_LOG_ERROR(g_logger) << "sock=" << m_sock << " connect(" << addr->toString()
                << ") timeout=" << timeout_ms << " error errno="
                << errno << " errstr=" << strerror(errno);
            close();
            return false;
        }
    }

    m_isConnected = true;   //建立连接
    getRemoteAddress();
    getLocalAddress();
    return true;
}


bool Socket::reconnect(uint64_t timeout_ms)
{
    return true;
}


/**
 * @brief 监听socket
 * @param[in] backlog 未完成连接队列的最大长度
 * @result 返回监听是否成功
 * @pre 必须先 bind 成功
 */
bool Socket::listen(int backlog)
{
    if(!isValid()) {
        FRAMEWORK_LOG_ERROR(g_logger) << "listen error m_sock=-1";
        return false;
    }
    if(::listen(m_sock, backlog))
    {
        FRAMEWORK_LOG_ERROR(g_logger) << "listen error errno=" << errno
            << " errstr=" << strerror(errno);
        return false;
    }
    return true;
}


//关闭socket
bool Socket::close()
{
    if(!m_isConnected && m_sock == -1)
    {
        return true;
    }

    m_isConnected = false;
    if(m_sock != -1)
    {
        ::close(m_sock);
        m_sock = -1;
    }
    return false;
}


/**
 * @brief 发送数据  TCP
 * @param[in] buffer 待发送数据的内存
 * @param[in] length 待发送数据的长度
 * @param[in] flags 标志字
 * @return
 *      @retval >0 发送成功对应大小的数据
 *      @retval =0 socket被关闭
 *      @retval <0 socket出错
 */
int Socket::send(const void* buffer, size_t length, int flags)
{
    if(isConnected())
    {
        return ::send(m_sock, buffer, length, flags);
    }
    return -1;
}


/**
 * @brief 发送数据  TCP
 * @param[in] buffers 待发送数据的内存(iovec数组)
 * @param[in] length 待发送数据的长度(iovec长度)
 * @param[in] flags 标志字
 * @return
 *      @retval >0 发送成功对应大小的数据
 *      @retval =0 socket被关闭
 *      @retval <0 socket出错
 */
int Socket::send(const iovec* buffers, size_t length, int flags)
{
    if(isConnected())
    {
        struct msghdr msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = (iovec*)buffers;
        msg.msg_iovlen = length;
        return ::sendmsg(m_sock, &msg, flags);
    }
    return -1;
}


/**
 * @brief 发送数据  UDP
 * @param[in] buffer 待发送数据的内存
 * @param[in] length 待发送数据的长度
 * @param[in] to 发送的目标地址
 * @param[in] flags 标志字
 * @return
 *      @retval >0 发送成功对应大小的数据
 *      @retval =0 socket被关闭
 *      @retval <0 socket出错
 */
int Socket::sendTo(const void* buffer, size_t length, const Address::ptr to, int flags)
{
    if(isConnected()) 
    {
        return ::sendto(m_sock, buffer, length, flags, to->getAddr(), to->getAddrLen());
    }
    return -1;
}


/**
 * @brief 发送数据  UDP
 * @param[in] buffers 待发送数据的内存(iovec数组)
 * @param[in] length 待发送数据的长度(iovec长度)
 * @param[in] to 发送的目标地址
 * @param[in] flags 标志字
 * @return
 *      @retval >0 发送成功对应大小的数据
 *      @retval =0 socket被关闭
 *      @retval <0 socket出错
 */
int Socket::sendTo(const iovec* buffers, size_t length, const Address::ptr to, int flags)
{
    if(isConnected()) {
        msghdr msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = (iovec*)buffers;
        msg.msg_iovlen = length;
        msg.msg_name = to->getAddr();
        msg.msg_namelen = to->getAddrLen();
        return ::sendmsg(m_sock, &msg, flags);
    }
    return -1;
}


/**
 * @brief 接受数据  TCP
 * @param[out] buffer 接收数据的内存
 * @param[in] length 接收数据的内存大小
 * @param[in] flags 标志字
 * @return
 *      @retval >0 接收到对应大小的数据
 *      @retval =0 socket被关闭
 *      @retval <0 socket出错
 */
int Socket::recv(void* buffer, size_t length, int flags)
{
    if(isConnected()) {
        return ::recv(m_sock, buffer, length, flags);
    }
    return -1;
}


/**
 * @brief 接受数据  TCP
 * @param[out] buffers 接收数据的内存(iovec数组)
 * @param[in] length 接收数据的内存大小(iovec数组长度)
 * @param[in] flags 标志字
 * @return
 *      @retval >0 接收到对应大小的数据
 *      @retval =0 socket被关闭
 *      @retval <0 socket出错
 */
int Socket::recv(iovec* buffers, size_t length, int flags)
{
    if(isConnected()) {
        msghdr msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = (iovec*)buffers;
        msg.msg_iovlen = length;
        return ::recvmsg(m_sock, &msg, flags);
    }
    return -1;
}


/**
 * @brief 接受数据  UDP
 * @param[out] buffer 接收数据的内存
 * @param[in] length 接收数据的内存大小
 * @param[out] from 发送端地址
 * @param[in] flags 标志字
 * @return
 *      @retval >0 接收到对应大小的数据
 *      @retval =0 socket被关闭
 *      @retval <0 socket出错
 */
int Socket::recvFrom(void* buffers, size_t length, Address::ptr from, int flags)
{
    if(isConnected()) {
        socklen_t len = from->getAddrLen();
        return ::recvfrom(m_sock, buffers, length, flags, from->getAddr(), &len);
    }
    return -1;
}


/**
 * @brief 接受数据  UDP
 * @param[out] buffers 接收数据的内存(iovec数组)
 * @param[in] length 接收数据的内存大小(iovec数组长度)
 * @param[out] from 发送端地址
 * @param[in] flags 标志字
 * @return
 *      @retval >0 接收到对应大小的数据
 *      @retval =0 socket被关闭
 *      @retval <0 socket出错
 */
int Socket::recvFrom(iovec* buffers, size_t length, Address::ptr from, int flags)
{
    if(isConnected()) {
        msghdr msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = (iovec*)buffers;
        msg.msg_iovlen = length;
        msg.msg_name = from->getAddr();
        msg.msg_namelen = from->getAddrLen();
        return ::recvmsg(m_sock, &msg, flags);
    }
    return -1;
}



//获取远端地址
Address::ptr Socket::getRemoteAddress()
{
    if(m_remoteAddress)
    {
        return m_remoteAddress;
    }

    Address::ptr result;
    switch (m_family)
    {
    case AF_INET:
        result.reset(new IPv4Address());
        break;
    case AF_INET6:
        result.reset(new IPv6Address());
        break;
    case AF_UNIX:
        result.reset(new UnixAddress());
        break;
    default:
        result.reset(new UnknownAddress(m_family));
        break;
    }

    socklen_t addrlen = result->getAddrLen();
    //获取本地的套接字信息
    if(getpeername(m_sock, result->getAddr(), &addrlen))
    {
        FRAMEWORK_LOG_ERROR(g_logger) << "getpeername error";
        return Address::ptr(new UnknownAddress(m_family));
    }
    if(m_family == AF_UNIX)
    {
        //将Address::ptr 转为 UnixAddress::ptr
        UnixAddress::ptr addr = std::dynamic_pointer_cast<UnixAddress>(result);
        addr->setAddrLen(addrlen);
    }

    m_remoteAddress = result;
    return m_remoteAddress;
}

//获取本地地址
Address::ptr Socket::getLocalAddress()
{
    if(m_localAddress)
    {
        return m_localAddress;
    }

    Address::ptr result;
    switch (m_family)
    {
    case AF_INET:
        result.reset(new IPv4Address());
        break;
    case AF_INET6:
        result.reset(new IPv6Address());
        break;
    case AF_UNIX:
        result.reset(new UnixAddress());
        break;
    default:
        result.reset(new UnknownAddress(m_family));
        break;
    }
    socklen_t addrlen = result->getAddrLen();
    //获取本地的套接字信息
    if(getsockname(m_sock, result->getAddr(), &addrlen))
    {
        FRAMEWORK_LOG_ERROR(g_logger) << "getsockname error sock=" << m_sock
            << " errno=" << errno << " errstr=" << strerror(errno);
        return Address::ptr(new UnknownAddress(m_family));
    }
    if(m_family == AF_UNIX)
    {
        //将Address::ptr 转为 UnixAddress::ptr
        UnixAddress::ptr addr = std::dynamic_pointer_cast<UnixAddress>(result);
        addr->setAddrLen(addrlen);
    }

    m_localAddress = result;
    return m_localAddress;
}

//是否有效(m_sock != -1)
bool Socket::isValid() const
{
    return m_sock != -1;
}

//返回Socket错误
int Socket::getError()
{
    int error = 0;
    socklen_t len = sizeof(error);
    if(!getOption(SOL_SOCKET, SO_ERROR, &error, &len))
    {
        error = errno;
    }

    return error;
}


//输出信息到流中
std::ostream& Socket::dump(std::ostream& os) const 
{
    os << "[Socket sock=" << m_sock
       << " is_connected=" << m_isConnected
       << " family=" << m_family
       << " type=" << m_type
       << " protocol=" << m_protocol;
    if(m_localAddress) {
        os << " local_address=" << m_localAddress->toString();
    }
    if(m_remoteAddress) {
        os << " remote_address=" << m_remoteAddress->toString();
    }
    os << "]";
    return os;
}

std::string Socket::toString() const
{
    std::stringstream ss;
    dump(ss);
    return ss.str();
}


//取消读
bool Socket::cancelRead()
{
    return IOManager::GetThis()->cancelEvent(m_sock, framework::IOManager::READ);
}

//取消写
bool Socket::cancelWrite()
{
    return IOManager::GetThis()->cancelEvent(m_sock, framework::IOManager::WRITE);
}

//取消accept
bool Socket::cancelAccept()
{
    return IOManager::GetThis()->cancelEvent(m_sock, framework::IOManager::READ);
}

//取消所有事件
bool Socket::cancelAll()
{
    return IOManager::GetThis()->cancelAll(m_sock);
}

//初始化socket  设置sock参数
void Socket::initSock()
{
    int val = 1;
    //SO_REUSEADDR一般服务器的监听socket都应该打开它, 去除time-wait等待时间导致连接失败
    setOption(SOL_SOCKET, SO_REUSEADDR, val);
    if(m_type == SOCK_STREAM) //如果是TCP
    {
        //TCP_NODELAY，该选项会禁用Nagle算法。Nagle算法的作用是减少小包的数量
        setOption(IPPROTO_TCP, TCP_NODELAY, val);
    }
}

//创建socket
void Socket::newSock()
{
    m_sock = socket(m_family, m_type, m_protocol);
    if(FRAMEWORK_LIKELY(m_sock != -1))
    {
        initSock();
    }
    else
    {
        FRAMEWORK_LOG_ERROR(g_logger) << "socket(" << m_family
            << ", " << m_type << ", " << m_protocol << ") errno="
            << errno << " errstr=" << strerror(errno);
    }
}

//==========================================================================


//流式输出socket
std::ostream& operator<<(std::ostream& os, const Socket& sock)
{
    return sock.dump(os);
}

} // namespace framework
